package com.xish.spring.aspect.session;

import com.xish.api.session.Session;
import com.xish.api.session.SessionRepository;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
@Aspect
public class CheckSessionAspect {

    private static final Logger LOG = LoggerFactory.getLogger(CheckSessionAspect.class);

    @Autowired
    private SessionRepository sessionRepository;

    @Pointcut("@annotation(com.xish.spring.aspect.session.CheckSession)")
    public void checkSessionPointcut() {
        // 这里定义一个AOP切点, 之后会引用到这个切点
    }


    // 在这个切点包含将被执行的函数
    @Around("checkSessionPointcut()")
    public Object checkSession(ProceedingJoinPoint pjp) throws Throwable {
        // 着重说明下必须抛出的都必须是RuntimeException

        MethodSignature methodSignature = (MethodSignature) pjp.getSignature();

        String[] paramNames = methodSignature.getParameterNames();
        if (paramNames.length < 1) {
            LOG.warn("no sessionId param exists.");
            throw new SessionException();
        }

        int sessionIdParamIndex = -1;    // 方法中参数名为sessionId的索引位置
        int sessionValueParamIndex = -1; // 方法中参数名为session的索引位置

        for (int index = 0; index < paramNames.length; index++) {
            String name = paramNames[index];
            if (name.equals("sessionId")) {
                sessionIdParamIndex = index;
            }

            if (name.equals("session")) {
                sessionValueParamIndex = index;
            }
        }

        if (sessionIdParamIndex == -1) {
            LOG.warn("no sessionId param exists.");
            throw new SessionException();
        }

        Object[] args = pjp.getArgs();

        String sessionId;
        try {
            sessionId = (String) args[sessionIdParamIndex];
        } catch (Exception e) {
            // maybe null pointer or array index exception
            LOG.error("sessionId param value exception.", e);
            throw new SessionException();
        }

        if ((sessionId == null) || sessionId.isEmpty()) {
            LOG.warn("empty sessionId value.");
            throw new SessionException();
        }

        Session session = sessionRepository.findById(sessionId);
        if (session == null) {
            LOG.warn("sessionId: {} not exists.", sessionId);
            throw new SessionException();
        }

        if (sessionValueParamIndex > -1) {
            // 如果方法中存在名称为session的参数, 进行赋值
            args[sessionValueParamIndex] = session;
        }

        return pjp.proceed(args);
    }
}
